package com.rslai.base.tool.servertest.database.postgresql;

import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.datatype.AbstractDataType;
import org.dbunit.dataset.datatype.StringDataType;
import org.dbunit.dataset.datatype.TypeCastException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ArrayDataType extends AbstractDataType {
    private static final Logger logger = LoggerFactory.getLogger(StringDataType.class);
    private String sqlTypeName;

    public ArrayDataType() {
        this("ARRAY", 2003);
    }

    public ArrayDataType(String name, int sqlType) {
        super(name, sqlType, Array.class, false);
        this.sqlTypeName = name;
    }

    public Object typeCast(Object value) throws TypeCastException {
        logger.debug("typeCast(value={}) - start", value);

        if ((value == null) || (value == ITable.NO_VALUE)) {
            return null;
        }

        if ((value instanceof String)) {
            return new String[]{(String) value};
        }
        if ((value instanceof String[])) {
            return value;
        }

        if (((value instanceof Date)) || ((value instanceof Time)) || ((value instanceof Timestamp))) {
            return new String[]{value.toString()};
        }

        if ((value instanceof Boolean)) {
            return new String[]{value.toString()};
        }

        if ((value instanceof Number)) {
            try {
                return new String[]{value.toString()};
            } catch (NumberFormatException e) {
                throw new TypeCastException(value, this, e);
            }
        }

        if ((value instanceof Array)) {
            try {
                Array a = (Array) value;
                return a.getArray();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        if ((value instanceof Blob)) {
            try {
                Blob blob = (Blob) value;
                byte[] blobValue = blob.getBytes(1L, (int) blob.length());
                return typeCast(blobValue);
            } catch (SQLException e) {
                throw new TypeCastException(value, this, e);
            }
        }

        if ((value instanceof Clob)) {
            try {
                Clob clobValue = (Clob) value;
                int length = (int) clobValue.length();
                if (length > 0) {
                    return clobValue.getSubString(1L, length);
                }
                return "";
            } catch (SQLException e) {
                throw new TypeCastException(value, this, e);
            }
        }

        logger.warn("Unknown/unsupported object type '{}' - will invoke toString() as last fallback which might produce undesired results", value.getClass().getName());

        return value.toString();
    }

    public Object getSqlValue(int column, ResultSet resultSet) throws SQLException, TypeCastException {
        if (logger.isDebugEnabled()) {
            logger.debug("getSqlValue(column={}, resultSet={}) - start", Integer.valueOf(column), resultSet);
        }
        String value = resultSet.getString(column);
        if ((value == null) || (resultSet.wasNull())) {
            return null;
        }
        return value;
    }

    public void setSqlValue(Object value, int column, PreparedStatement statement) throws SQLException, TypeCastException {
        if (logger.isDebugEnabled()) {
            logger.debug("setSqlValue(value={}, column={}, statement={}) - start", new Object[]{value, Integer.valueOf(column), statement});
        }

        Array array = statement.getConnection().createArrayOf(this.sqlTypeName.substring(1), toArray(value));
        Map map = new HashMap();
        map.put("", null);
        statement.setObject(column, new PGHStore(map));
        statement.setArray(column, array);
    }

    private Object[] toArray(Object value) {
        List list = new ArrayList(0);
        if ((value instanceof String)) {
            String valueStr = (String) value;
            if (StringUtils.isNotBlank(valueStr)) {
                valueStr = valueStr.replaceAll("[{}]", "");
                return valueStr.split(",");
            }
        }
        return list.toArray();
    }
}
